#include <iostream>
#include <vector>
#include <iomanip>
#include <fstream>
#include <pthread.h>
#include <stdlib.h>

using namespace std;

//Prototipos
void CrearMatrizT(double);
void inicializarMatrizT();
void inicializarAux();
void imprimitMatrizT();
void imprimitMatrizUA();
void* productoMatrizTVectorU(void*);

//Variables Globales
vector<double> matrizU;
vector<double> matrizT;
vector<double> aux;
vector< vector<double> > matrizUA;
int sizeIni;

int main(int argc, char **argv) {
	double z;
	double var;
	int nh,*par;
	int tamb;
	void *p;
	pthread_t *hilos;
	cout<<endl<<"\t\tIntroduzca el valor de Z (Z=C*dt/h^2):"<<endl;
	cin>>z;
	if(z>0.5){
			cout<<"ERROR! z>0.5 introduzca un valor de z diferente"<<endl;
			return 0;
	}
	cout<<endl<<"\t\tIntroduzca las condiciones iniciales de la barra -1-->Terminar"<<endl;
	cin>>var;
	while(var!=-1){
		matrizU.push_back(var);
		cin>>var;
	}
	sizeIni=matrizU.size();
	tamb=sizeIni;
	inicializarMatrizT();
	inicializarAux();
	CrearMatrizT(z);
	cout<<endl<<"\t\tMatriz T"<<endl;
	imprimitMatrizT();
	matrizUA.push_back(matrizU);
	nh = tamb;
	hilos= new pthread_t[nh];
	for(int j=0; j< 1000; j++){
		for(int i=0; i < nh ; i++){
			par=new int (i);
			pthread_create(&hilos[i],NULL,productoMatrizTVectorU,(void *)par);
		}
		for(int k=0;k<nh;k++)//esperar a que los hilos terminen.
			pthread_join(hilos[k], &p);
		matrizUA.push_back(aux);
		matrizU=aux;
	}
	imprimitMatrizUA();
	system("gnuplot splot.gp");
	system("eog aux.png");

}

//Definicion de Funciones
void inicializarMatrizT(){
	for(int i=0;i<sizeIni*sizeIni;i++){
		matrizT.push_back(0);
	}
}
void inicializarAux(){
	for(int i=0;i<sizeIni;i++){
		aux.push_back(0);
	}
}
void CrearMatrizT(double z){
	int size=sizeIni;
	for(int i=0;i<size;i++){
		if(i==0){
			matrizT[i+1]=z;
			matrizT[i]=1-2*z;
		}
		else if(i==size-1){
			matrizT[size*size-2]=z;
			matrizT[size*size-1]=1-2*z;
		}
		else{
			matrizT[size*i+i-1]=z;
			matrizT[size*i+i]=1-2*z;
			matrizT[size*i+i+1]=z;

		}
	}
}
void imprimitMatrizT(){
	for(int i=0;i<matrizT.size();i++){
				cout<<setw(5)<<setprecision(2)<<matrizT[i]<<setw(5);
				if((i+1)%sizeIni==0){
					cout<<endl;
				}
		}
}
void imprimitMatrizUA(){
	fstream salida("salida.txt",ios::out);
vector<vector<double> >::iterator p=matrizUA.begin();
vector<double>::iterator q;
int i=0,j=0;
while(p!=matrizUA.end()){
        vector<double> aux=*p;
        q=aux.begin();
        j=0;
        while(q!= aux.end()){
                salida <<i<<" "<<j<<" "<< *q<<endl;
        q++;
        j++;
        }
p++;
i++;
}
}
void* productoMatrizTVectorU(void *var){
	int *varLoc=(int*) var;
	double sum=0;
	int j=0;
		for(int i=sizeIni*(*varLoc); i<matrizT.size(); i++) {
	    		sum+=matrizT[i]*matrizU[j];
	    		j++;
	        if((i+1)%sizeIni==0){
	    	 	 aux[*varLoc]=sum;
	    	 	pthread_exit(NULL);
	     	 }
		}
	}
